package org.dtrd.modules.device.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.api.vo.Result;
import org.dtrd.common.util.CheckUtil;
import org.dtrd.config.system.SystemState;
import org.dtrd.modules.device.config.DeviceConstant;
import org.dtrd.modules.device.entity.bean.DeviceDetail;
import org.dtrd.modules.device.entity.bean.DeviceListInfo;
import org.dtrd.modules.device.entity.po.DtrdEntRdDevice;
import org.dtrd.modules.device.entity.request.BindDeviceRequest;
import org.dtrd.modules.device.entity.request.DeviceListRequest;
import org.dtrd.modules.device.entity.request.DevicePageRequest;
import org.dtrd.modules.device.mapper.DtrdEntRdDeviceMapper;
import org.dtrd.modules.device.service.IDtrdEntRdDeviceService;
import org.dtrd.modules.device.util.MD5Util;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xiao
 * @since 2022-01-11
 */
@DS("multi-datasource1")
@Service
@Slf4j
public class DtrdEntRdDeviceServiceImpl extends ServiceImpl<DtrdEntRdDeviceMapper, DtrdEntRdDevice> implements IDtrdEntRdDeviceService {

    @Override
    public List<DeviceListInfo> getDeviceList(DeviceListRequest request) {
        LambdaQueryWrapper<DtrdEntRdDevice> queryWrapper = baseQueryWrapper();
        List<DtrdEntRdDevice> poList = list(queryWrapper);
        List<DeviceListInfo> dtoList = new ArrayList<>(poList.size());
        if (!poList.isEmpty()) {
            dtoList = poList.stream().map(DeviceListInfo::new).collect(Collectors.toList());
        }
        return dtoList;
    }

    @Override
    public IPage<DeviceListInfo> pageDevice(DevicePageRequest request) {
        LambdaQueryWrapper<DtrdEntRdDevice> queryWrapper = baseQueryWrapper();
        IPage<DtrdEntRdDevice> page = new Page<>(request.getPageNum(), request.getPageSize());
        page = this.page(page, queryWrapper);
        return page.convert(DeviceListInfo::new);
    }

    @Override
    public DeviceDetail getDevice(Integer dataId) {
        DtrdEntRdDevice dtrdEntRdDevice = getById(dataId);
        return Optional.ofNullable(dtrdEntRdDevice)
                .map(po -> new DeviceDetail().parseFromPo(po))
                .orElse(null);
    }

    @Override
    public boolean saveOrUpdateDevice(DeviceDetail dto) {
        DtrdEntRdDevice dtrdEntRdDevice = new DtrdEntRdDevice();
        if (dto.getDataId() == null) {
            dtrdEntRdDevice = dtrdEntRdDevice.init();
        }
        dtrdEntRdDevice.parseFromDto(dto);
        return saveOrUpdate(dtrdEntRdDevice);
    }

    @Override
    public boolean removeDevice(Integer dataId) {
        return removeById(dataId);
    }

    private LambdaQueryWrapper<DtrdEntRdDevice> baseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdEntRdDevice.class)
                .eq(DtrdEntRdDevice::getIsDel, 0);
    }

    private LambdaUpdateWrapper<DtrdEntRdDevice> baseUpdateWrapper() {
        return Wrappers.lambdaUpdate(DtrdEntRdDevice.class)
                .eq(DtrdEntRdDevice::getIsDel, 0);
    }

    /**
     * 设备操作 解绑、绑定
     *
     * @param request
     * @return
     */
    @Override
    public Result<?> bindDevice(BindDeviceRequest request) {
        if (DeviceConstant.BindState.isBind(request.getOperation())) {
            return doBind(request);
        } else {
            return doUnbind(request);
        }
    }

    /**
     * 执行绑定逻辑
     *
     * @param request
     * @return
     */
    private Result<?> doBind(BindDeviceRequest request) {
        // 查询用户绑定记录
        DtrdEntRdDevice recordByPatientId = baseMapper.selectRecordByCondition(request.getPatientId(), null, DeviceConstant.BindState.BIND.getState(), request.getDeviceBrand(), request.getDeviceCategory());
        // 查询设备关联记录
        DtrdEntRdDevice recordBySn = baseMapper.selectRecordByCondition(null, request.getDeviceSn(), DeviceConstant.BindState.BIND.getState(), request.getDeviceBrand(), request.getDeviceCategory());
        log.info("DtrdEntRdDeviceServiceImpl.doBind.[request] recordBySn = " + recordBySn + " ; recordByPatientId = " + recordByPatientId);
        if (recordByPatientId == null && recordBySn == null) {
            // 用户未曾绑定设备 设备未曾绑定用户
            // 完成绑定
            saveRecord(request);
            return Result.OK(SystemState.ResponseState.STATE_SUCCESS.getMsg());
        } else if (recordByPatientId != null && recordBySn != null) {
            // 用户已绑定设备 设备已绑定用户
            if (recordByPatientId.getDataId().equals(recordBySn.getDataId())) {
                // 判断用户与设备关联一致
                //不作处理返回成功
                return Result.OK(SystemState.ResponseState.STATE_SUCCESS.getMsg());
            } else {
                return Result.error(SystemState.ResponseState.STATE_DATA_ERROR.getCode(), SystemState.ResponseState.STATE_DATA_ERROR.getMsg());
            }
        } else {
            // 设备已绑定 或者 用户已绑定
            if (recordBySn != null) {
                return Result.error(SystemState.ResponseState.STATE_OPERATION_FAILURE.getCode(), "设备已绑定其他用户，不能重复绑定");
            } else {
                return Result.error(SystemState.ResponseState.STATE_OPERATION_FAILURE.getCode(), "用户已绑定其他设备，不能重复绑定");
            }
        }
    }

    /**
     * 设备解绑
     *
     * @param request
     * @return
     */
    private Result<?> doUnbind(BindDeviceRequest request) {
        DtrdEntRdDevice record = baseMapper.selectRecordByCondition(request.getPatientId(), request.getDeviceSn(), DeviceConstant.BindState.BIND.getState(), request.getDeviceBrand(), request.getDeviceCategory());
        if (record != null) {
            // 查询当前关联状态 执行解绑
            record.setDeviceBindState(DeviceConstant.BindState.UNBIND.getState());
            baseMapper.updateById(record);
        }
        return Result.OK(SystemState.ResponseState.STATE_SUCCESS.getMsg());
    }

    /**
     * 插入绑定记录
     *
     * @param request
     */
    private void saveRecord(BindDeviceRequest request) {
        Integer patientId = request.getPatientId();
        String deviceSn = request.getDeviceSn();
        DtrdEntRdDevice entity = new DtrdEntRdDevice();
        entity.setCreateTime(new Date());
        entity.setUserId(patientId);
        entity.setDeviceSn(deviceSn);
        entity.setDeviceImei(CheckUtil.isEmpty(request.getDeviceImei()) ? deviceSn : request.getDeviceImei());
        entity.setDeviceImsi(request.getDeviceImsi());
        entity.setDeviceBindState(DeviceConstant.BindState.BIND.getState());
        entity.setDeviceCategory(request.getDeviceCategory());
        entity.setDeviceBrand(request.getDeviceBrand());
        baseMapper.insert(entity);
    }

    /**
     * 根据设备序列号和设备类型查询绑定记录
     *
     * @param serialNumber   序列号
     * @param deviceBrand    设备品牌
     * @param deviceCategory 设备类型
     * @return
     */
    @Override
    public DtrdEntRdDevice selectOntByDeviceSnAndDeviceType(String serialNumber, Integer deviceBrand, Integer deviceCategory) {
        return baseMapper.selectRecordByCondition(null, serialNumber, DeviceConstant.BindState.BIND.getState(), deviceBrand, deviceCategory);
    }

    @Override
    public DtrdEntRdDevice getBindRecord(Integer patientId, Integer deviceBrand, Integer deviceCategory) {
        return baseMapper.selectRecordByCondition(patientId, null, DeviceConstant.BindState.BIND.getState(), deviceBrand, deviceCategory);
    }

    @Override
    public boolean checkWeiceSignature(String signature, String body) {
        log.info("DtrdEntRdDeviceServiceImpl.checkWeiceSignature.[signature, body] " + MD5Util.MD5Encode(body + DeviceConstant.WeiceConfig.WEICE_SALT));
        return MD5Util.MD5Encode(body + DeviceConstant.WeiceConfig.WEICE_SALT).equals(signature);
    }

    @Override
    public List<DeviceListInfo> getBindDevice(Integer patientId) {
        List<DtrdEntRdDevice> list = baseMapper.getBindDevice(patientId, DeviceConstant.BindState.BIND.getState());
        if (list != null) {
            List<DeviceListInfo> dataList = new ArrayList<>(list.size());
            list.stream().map(DeviceListInfo::new).forEach(dataList::add);
            return dataList;
        }
        return null;
    }

}
